package com.newlink.building.manager

import android.annotation.SuppressLint
import android.content.Context
import android.content.Intent
import android.os.Handler
import android.os.Looper
import android.view.TextureView
import com.newlink.building.common_base.base.BaseApplication
import com.newlink.building.common_base.base.BaseApplication.Companion.context
import com.newlink.building.common_base.constant.Base_Constant
import com.newlink.building.common_base.constant.Base_DeviceType
import com.newlink.building.common_base.constant.NL_Key
import com.newlink.building.common_base.ext.showToast
import com.newlink.building.common_base.model.bean.KcpInfoData
import com.newlink.building.common_base.utils.NLog
import com.newlink.building.common_base.utils.Base_Preference
import com.newlink.building.common_base.utils.SingletonHolder
import com.newlink.building.NL_App
import com.newlink.building.R
import com.newlink.building.activities.Module_Phone_MonitorActivityNL
import com.newlink.building.activities.call.Module_Phone_CallActivity
import com.newlink.building.activities.call.Module_Phone_IncomingCallActivity
import com.newlink.building.activities.call.Module_Phone_OutgoingCallActivity
import com.newlink.building.callback.Module_Phone_CallStateCallback
import com.newlink.building.callback.Module_Phone_RegistrationCallback
import com.newlink.building.core.Module_Phone_CoreContext
import com.newlink.building.core.Module_Phone_CorePreferences
import com.newlink.building.utils.Module_Phone_AppUtils.Companion.getString
import com.newlink.building.utils.Module_Phone_Base64Utils
import com.newlink.building.utils.Module_Phone_LinphoneUtils
import com.newlink.building.obfuscation.Module_Obfuscation_ObfuscationHelper
import com.newlink.building.obfuscation.Module_Obfuscation_ObfuscationInvoker
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import org.linphone.core.Account
import org.linphone.core.AudioDevice
import org.linphone.core.Call
import org.linphone.core.Core
import org.linphone.core.CoreListenerStub
import org.linphone.core.Factory
import org.linphone.core.MediaDirection
import org.linphone.core.MediaEncryption
import org.linphone.core.Reason
import org.linphone.core.RegistrationState
import org.linphone.core.TransportType
import org.linphone.core.tools.Log
import java.io.File
import java.util.concurrent.CopyOnWriteArrayList

/**
 * Created by xiaodong on 2022/8/9.
 * Linphone管理类
 */
class Module_Phone_VoipController private constructor(context: Context) {


    /**
     * sip服务地址
     */
    var domainAdress: String by Base_Preference(Base_Constant.DOMAIN_ADDRESS, "127.0.0.1")

    /**
     * realm域地址
     */
    var realmAdress: String by Base_Preference(Base_Constant.REALM_ADDRESS, "")

    /**
     * 单例
     */
    companion object : SingletonHolder<Module_Phone_VoipController, Context>(::Module_Phone_VoipController)

    /**
     * 账号注册状态
     */
    var registrationCallback: Module_Phone_RegistrationCallback? = null
    var registerList: MutableList<Module_Phone_RegistrationCallback> = mutableListOf()

    /**
     * 所有通话状态监听
     */
    private var callStateCallBacks: CopyOnWriteArrayList<Module_Phone_CallStateCallback> = CopyOnWriteArrayList()

    /**
     * 用户是否在线
     */
    var isOnLine: Boolean = false

    private var callTimeoutHandler: Handler? = null
    private var callTimeoutRunnable: Runnable? = null

    // 30 seconds
    private val callTimeoutDuration: Long = 2 * 60 * 1000

    /**
     * 对core的封装,通过coreContext.core获取
     */
    @SuppressLint("StaticFieldLeak")
    var coreContext: Module_Phone_CoreContext = NL_App.coreContext

    /**
     * core相关配置
     */
    @SuppressLint("StaticFieldLeak")
    var corePreferences: Module_Phone_CorePreferences = NL_App.corePreferences

    private var kcpInfoData: KcpInfoData by Base_Preference(
        Base_Constant.KCP_INFO_KEY,
        KcpInfoData()
    )

    fun setRegisterCallback(registrationCallback: Module_Phone_RegistrationCallback) {
        registerList.add(registrationCallback)
    }

    fun unRegisterCallback(registrationCallback: Module_Phone_RegistrationCallback) {
        if (registerList.contains(registrationCallback)) {
            registerList.remove(registrationCallback)
        }
    }

    /**
     * sip账号注册
     */
    fun registerAccount(
        username: String,
        password: String = "",
        domain: String = "127.0.0.1",
        port: String = "5060",
        realm: String = "",
        displayName: String? = "",
    ) {
        val defaultAccount = coreContext.core.defaultAccount
        NLog.d("registerAccount username:$username,defaultAccount:${defaultAccount?.findAuthInfo()?.username}")
        if (defaultAccount != null && defaultAccount.findAuthInfo()?.username == username) {
            return
        }
        val authInfo =
            Factory.instance().createAuthInfo(username, username, password, null, realm, domain)

        coreContext.core.addAuthInfo(authInfo)
        val accountParams = coreContext.core.createAccountParams()

        val realm = if (realm.isNotEmpty()) realm else domain
        val identity = Factory.instance().createAddress("sip:$username@$realm")
        val legalDisplayName = replaceSpecialSymbol(displayName)
        displayName?.let {
            //防止displayName过长导致sip注册失败问题
            if (it.length > 64) {
                identity?.displayName = it.substring(0, 64).plus("...")
            } else {
                identity?.displayName = legalDisplayName
            }
        }

        identity?.port = if (!port.isNullOrEmpty()) port.toInt() else 5060
        accountParams.identityAddress = identity

        NLog.d("identity ${identity?.asStringUriOnly()}")
        val address = Factory.instance().createAddress("sip:$domain")
        if (port.isNotEmpty()) {
            address?.port = port.toInt()
        }
        address?.transport = TransportType.Udp

        accountParams.serverAddress = address
        accountParams.isRegisterEnabled = true

        if (realm.isNotEmpty()) {
            accountParams.isOutboundProxyEnabled = true
            accountParams.realm = realm
        }

        val account = coreContext.core.createAccount(accountParams)

        coreContext.core.addAccount(account)
        coreContext.core.defaultAccount = account

        account.addListener { _, state, message ->
            when (state) {
                RegistrationState.Failed -> {
//                    showToast(context.getString(R.string.sip_registration_failed))
                }

                RegistrationState.Ok -> {
                    NLog.d("RegistrationState Ok  Call-ID ${account.getCustomHeader("Call-ID")}}")
                }

                else -> {}
            }
            NLog.i("state$state message$message")
        }

        autoAcceptVideo(true)

        coreContext.core.setPreferredVideoDefinitionByName("VGA")
        coreContext.core.start()
        val isLinphoneAccount = domain == corePreferences.defaultDomain
        coreContext.newAccountConfigured(isLinphoneAccount)
        savePasswordToPref(password)

        //关闭STUN开关
//        initStunParams(account)
    }

    fun replaceSpecialSymbol(text: String?): String {
        var replaceStr = text.orEmpty()
        if (replaceStr.contains("@")) {
            replaceStr = replaceStr.replace("@", "\u200B")
        }
        NLog.e("replaceSpecialSymbol $replaceStr")
        return replaceStr
    }

    fun recoverSpecialSymbol(name: String?): String {
        var displayName = name.orEmpty()
        if (displayName.contains("\u200B")) {
            displayName = displayName.replace("\u200B", "@")
        }
        NLog.e("recoverSpecialSymbol $displayName")
        return displayName
    }

    private fun initStunParams(account: Account) {
        val params = account.params.clone()
        val natPolicy = coreContext.core.createNatPolicy()
        natPolicy.stunServer = "${kcpInfoData.stunaddr}:${kcpInfoData.stunport}"
        natPolicy.isIceEnabled = true
        params.natPolicy = natPolicy

        params.natPolicy?.isTurnEnabled = true
        params.natPolicy?.isStunEnabled = true
        params.natPolicy?.stunServerUsername = kcpInfoData.turnuser
//        params.natPolicy?.turnServerPassword = kcpInfoData.turnpwd
        account.params = params
    }

    private fun savePasswordToPref(pwd: String) {
        corePreferences.storePresenceInNativePassword = Module_Phone_Base64Utils.encodeToString(pwd)
    }

    /**
     * 退出sip账号
     */
    fun unregister() {
        // SIP账号退出时的混淆
        Module_Obfuscation_ObfuscationHelper.onMethodEnter("VoipController", "unregister")
        Module_Obfuscation_ObfuscationInvoker.invokeRandom(System.currentTimeMillis())

        val account = coreContext.core.defaultAccount
        account ?: return
        val params = account.params
        val cloneParams = params.clone()
        cloneParams.isRegisterEnabled = false
        account.params = cloneParams
    }

    /**
     * 删除sip账号
     */
    fun delete() {
        val accountList = coreContext.core.accountList
        if (accountList.isNotEmpty()) {
            for (account in accountList) {
                coreContext.core.removeAccount(account)
                coreContext.core.clearAccounts()
                coreContext.core.clearAllAuthInfo()
            }
        }
    }


    fun answer() {
        val core = coreContext.core
        if (core.callsNb == 0) return
        val call = if (core.currentCall != null) core.currentCall else core.calls[0]
        call ?: return
//        call.accept()
        val params = core.createCallParams(call)
        call.acceptWithParams(params)

    }

    /**
     * 挂断当前通话
     */
    fun hangUp(): Boolean {
        // 挂断电话时的混淆
        Module_Obfuscation_ObfuscationHelper.onMethodEnter("VoipController", "hangUp")
        Module_Obfuscation_ObfuscationInvoker.invokeRandom("hangup")

        NLog.d("hangUp...")
        val core = coreContext.core
        if (core.callsNb == 0) {
            NLog.e("No call in progress invoke callEnd method")
            callEnd(null)
            return false
        }

        val call = if (core.currentCall != null) core.currentCall else core.calls[0]
        call ?: return false
        call.terminate()
        NLog.d("hangUp..ok.")
        return true
    }

    /**
     * 获取当前通话数量
     */
    fun getCallsNb() = coreContext.core.callsNb

    /**
     * 判断当前是否有通话中
     */
    fun isCallingState(): Boolean {
        NLog.d(" isCallingState  callNb:${getCallsNb()} callState:${coreContext.core.currentCall?.state}")
        if (getCallsNb() > 0) {
            val callState = coreContext.core.currentCall?.state
            if (callState == Call.State.Connected
                || callState == Call.State.StreamsRunning
                || callState == Call.State.OutgoingInit
                || callState == Call.State.OutgoingProgress
                || callState == Call.State.OutgoingRinging
                || callState == Call.State.OutgoingEarlyMedia
                || callState == Call.State.IncomingReceived
                || callState == Call.State.IncomingEarlyMedia
            ) {
                return true
            }
        }
        return false
    }

    /**
     * 拨打语音通话
     */
    fun makeAudioCall(username: String, displayName: String? = "") {
        if (username.isNullOrEmpty()) {
            return
        }
        android.util.Log.e("yxd", "makeAudioCall $username $displayName")
        ensureIpv6Disabled()
        val remoteAdress = if (realmAdress.isEmpty()) domainAdress else realmAdress
        var remoteSipUri = formatSipAddress(username, remoteAdress)
        NLog.i("makeAudioCall remoteSipUri $remoteSipUri username $username")
        val remoteAddress = Factory.instance().createAddress(remoteSipUri)
        remoteAddress ?: return

        var params = coreContext.core.createCallParams(null)
        params ?: return

        NLog.e("[VoipController]....<jake>..callTimeoutRunnable... 1111111111111111")
        params.sessionName = displayName
        params?.isVideoEnabled = false
        params.mediaEncryption = MediaEncryption.None
        coreContext.core.inviteAddressWithParams(remoteAddress, params)

        setCallTimeout()
    }

    private fun setCallTimeout() {

        if (callTimeoutRunnable != null) {
            callTimeoutHandler?.removeCallbacks(callTimeoutRunnable!!)
        }
        callTimeoutRunnable = Runnable {
            val currentCall = coreContext.core.currentCall
            NLog.e("[VoipController]......callTimeoutRunnable... ${currentCall?.state}")
            if (currentCall != null && currentCall.state == Call.State.OutgoingRinging) {
                currentCall.terminate()
            }
        }
        NLog.e("[VoipController]......setCallTimeout")
        callTimeoutHandler?.postDelayed(callTimeoutRunnable!!, callTimeoutDuration)
    }

    fun sinceLastCallEndTime(): Long {
        val currentTimeMillis = System.currentTimeMillis()
        val callEndTimeMillis = NL_App.coreContext.callEndTimeMillis.value
        var sinceLastTime = currentTimeMillis - (callEndTimeMillis ?: 0)
        NLog.e("[VoipController]....<jake>..sinceLastCallEndTime... sinceLastTime:$sinceLastTime")
        return sinceLastTime
    }

    /**
     * 拨打视频通话
     */
    fun makeVideoCall(
        username: String,
        displayName: String? = "",
        type: Int = Base_DeviceType.DOORPHONE.code
    ) {
        NLog.e("[VoipController]....<jake>..callTimeoutRunnable... 22222222222")
        ensureIpv6Disabled()
        val remoteAdress = if (realmAdress.isEmpty()) domainAdress else realmAdress
        var remoteSipUri = formatSipAddress(username, remoteAdress)
        NLog.i("makeVideoCall remoteSipUri $remoteSipUri")
        val remoteAddress = Factory.instance().createAddress(remoteSipUri)
        remoteAddress ?: return

        var params = coreContext.core.createCallParams(null)
        params ?: return

        params.isVideoEnabled = true
        params.audioDirection = MediaDirection.SendRecv
        params.videoDirection = MediaDirection.RecvOnly
        params.recordFile = Module_Phone_LinphoneUtils.getRecordingFilePathForAddress(remoteAddress)


//        val policy = coreContext.core.videoActivationPolicy
//        policy.automaticallyAccept = true
//        policy.automaticallyInitiate = true
//        coreContext.core.videoActivationPolicy = policy
//        coreContext.core.videoActivationPolicy.automaticallyAccept
        coreContext.core.isVideoCaptureEnabled = true
        coreContext.core.isVideoDisplayEnabled = true


        params.sessionName = displayName
        params.mediaEncryption = MediaEncryption.None
        coreContext.core.inviteAddressWithParams(remoteAddress, params)
        setCallTimeout()
        NLog.d("params ${params.isVideoEnabled}")
        NLog.e("jake ===>  params ${coreContext.core.currentCall?.currentParams}")
    }

    /**
     * make call方式实现监控
     */
    fun makeMonitorCall(
        username: String,
        displayName: String? = "",
        type: Int = Base_DeviceType.DOORPHONE.code
    ) {
        ensureIpv6Disabled()
        val remoteAdress = if (realmAdress.isEmpty()) domainAdress else realmAdress
        var remoteSipUri = formatSipAddress(username, remoteAdress)
        NLog.i("makeMonitorCall remoteSipUri $remoteSipUri")
        val remoteAddress = Factory.instance().createAddress(remoteSipUri)
        remoteAddress ?: return

        var params = coreContext.core.createCallParams(null)
        params ?: return

        params?.isVideoEnabled = true
        params.addCustomHeader(NL_Key.CALL_INFO, NL_Key.EXTRA_MONITOR)
        params.sessionName = displayName
        params.recordFile = Module_Phone_LinphoneUtils.getRecordingFilePathForAddress(remoteAddress)

        coreContext.core.isVideoCaptureEnabled = true
        coreContext.core.isVideoDisplayEnabled = true

        params.mediaEncryption = MediaEncryption.None
        coreContext.core.inviteAddressWithParams(remoteAddress, params)
        NLog.d("params ${params.isVideoEnabled}")
    }

    /**
     * 拨打语音通话根据完整远端sip地址
     */
    fun makeAudioCallWholeAdress(remoteSipUri: String) {
        NLog.i("makeAudioCallWholeAdress remoteSipUri $remoteSipUri")
        val remoteAddress = Factory.instance().createAddress(remoteSipUri)
        remoteAddress ?: return

        var params = coreContext.core.createCallParams(null)
        params ?: return

        params?.isVideoEnabled = false
        params.mediaEncryption = MediaEncryption.None
        coreContext.core.inviteAddressWithParams(remoteAddress, params)
    }


    /**
     * 拨打视频通话根据完整远端sip地址
     */
    fun makeVideoCallWholeAdress(remoteSipUri: String) {
        NLog.i("makeVideoCallWholeAdress remoteSipUri $remoteSipUri")
        val remoteAddress = Factory.instance().createAddress(remoteSipUri)
        remoteAddress ?: return

        var params = coreContext.core.createCallParams(null)
        params ?: return

        params?.isVideoEnabled = true
        params.recordFile = Module_Phone_LinphoneUtils.getRecordingFilePathForAddress(remoteAddress)

//        val policy = coreContext.core.videoActivationPolicy
//        policy.automaticallyAccept = true
//        policy.automaticallyInitiate = true
//        coreContext.core.videoActivationPolicy = policy
//        coreContext.core.videoActivationPolicy.automaticallyAccept
        coreContext.core.isVideoCaptureEnabled = true
        coreContext.core.isVideoDisplayEnabled = true

        params.mediaEncryption = MediaEncryption.None
        coreContext.core.inviteAddressWithParams(remoteAddress, params)
        NLog.d("params ${params.isVideoEnabled}")
    }

    /**
     * 远程用户sip格式拼接
     * eg. username@domain or username@realm
     */
    private fun formatSipAddress(username: String, serverName: String): String {
        return "sip:$username@$serverName"
    }

    fun addCallStateCallBack(callStateCallback: Module_Phone_CallStateCallback) {
        callStateCallBacks.add(callStateCallback)
    }

    fun removeCallStateCallBack(callStateCallback: Module_Phone_CallStateCallback) {
        callStateCallBacks.remove(callStateCallback)
    }

    /**
     * core相关状态的监听
     */
    private val coreListener = object : CoreListenerStub() {

        override fun onAccountRegistrationStateChanged(
            core: Core,
            acount: Account,
            state: RegistrationState?,
            message: String
        ) {
            NLog.d("onAccountRegistrationStateChanged  acount:${acount.params.identityAddress?.username}  state:$state message:$message")
            notifyAllRegisters(state)
//            when (state) {
//                RegistrationState.None -> registrationCallback?.registrationNone()
//                RegistrationState.Progress -> registrationCallback?.registrationProgress()
//                RegistrationState.Ok -> {
//                    registrationCallback?.registrationOk()
//                    isOnLine = true
//                }
//                RegistrationState.Cleared -> {
//                    registrationCallback?.registrationCleared()
//                    isOnLine = false
//                }
//                RegistrationState.Failed -> {
//                    registrationCallback?.registrationFailed()
//                    isOnLine = false
//                }
//            }
        }

        override fun onLastCallEnded(core: Core) {
            super.onLastCallEnded(core)
            NLog.d("onLastCallEnded")
        }

        override fun onCallStateChanged(
            core: Core,
            call: Call,
            state: Call.State?,
            message: String
        ) {
            NLog.d("onCallStateChanged ${call.state}")
            when (call.state) {
                Call.State.IncomingReceived, Call.State.IncomingReceived -> onIncomingReceived(call)
                Call.State.OutgoingInit -> onOutgoingStarted(call)
                Call.State.Connected -> callConnected(call)
                Call.State.End, Call.State.Error, Call.State.Released -> {
                    when (call.state) {
                        Call.State.End -> callEnd(call)
                        Call.State.Released -> callReleased(call)
                        Call.State.Error -> callError(call)
                        else -> {}
                    }
                    callTimeoutRunnable?.let {
                        callTimeoutHandler?.removeCallbacks(it)
                    }
                }

                Call.State.UpdatedByRemote -> updatedByRemote(call)
                Call.State.StreamsRunning -> streamsRunning(call)
                else -> {}
            }
        }
    }

    private fun notifyAllRegisters(state: RegistrationState?) {
        for (registrationCallback in registerList) {
            when (state) {
                RegistrationState.None -> registrationCallback?.registrationNone()
                RegistrationState.Progress -> registrationCallback?.registrationProgress()
                RegistrationState.Ok -> {
                    registrationCallback?.registrationOk()
                    isOnLine = true
                }

                RegistrationState.Cleared -> {
                    registrationCallback?.registrationCleared()
                    isOnLine = false
                }

                RegistrationState.Failed -> {
                    registrationCallback?.registrationFailed()
                    isOnLine = false
                }

                else -> {}
            }
        }
    }

    private fun onIncomingReceived(call: Call) {
        NLog.i("[Context] Starting IncomingCallActivity")

        Intent(context, Module_Phone_IncomingCallActivity::class.java).run {
            addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
            context.startActivity(this)
        }

        for (callBack in callStateCallBacks) {
            callBack.incommingCall(call)
        }
    }

    private fun onOutgoingStarted(call: Call) {
        NLog.i("[Context] Starting OutgoingCallActivity")

        Intent(context, Module_Phone_OutgoingCallActivity::class.java).run {
            addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_REORDER_TO_FRONT)
            context.startActivity(this)
        }

        for (callBack in callStateCallBacks) {
            callBack.incommingCall(call)
        }
    }

    private fun jumpToDestinationCall(call: Call) {
        val videoEnabled = call.params.isVideoEnabled
        val type = call.params.getCustomHeader(NL_Key.CALL_INFO)
        NLog.e("jumpToDestinationCall videoEnabled:$videoEnabled  type:$type")
//            val cls =
//                if (videoEnabled) VideoCallActivity::class.java else AudioCallActivity::class.java
        val cls = if (videoEnabled) {
            if (type == NL_Key.EXTRA_MONITOR) {
                Module_Phone_MonitorActivityNL::class.java
            } else {
                Module_Phone_CallActivity::class.java
            }
        } else {
            Module_Phone_CallActivity::class.java
        }

        Intent(context, cls).run {
            addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_REORDER_TO_FRONT)
            context.startActivity(this)
        }
    }

    private fun streamsRunning(call: Call) {

    }

    private fun callConnected(call: Call) {
        jumpToDestinationCall(call)
        for (callBack in callStateCallBacks) {
            callBack.callConnected(call)
        }
    }

    private fun callEnd(call: Call?) {
        for (callBack in callStateCallBacks) {
            callBack.callEnd(call)
        }
    }

    private fun callReleased(call: Call) {
        for (callBack in callStateCallBacks) {
            callBack.callReleased(call)
        }
    }

    private fun callError(call: Call) {
        for (callBack in callStateCallBacks) {
            callBack.callError(call)
        }
    }

    private fun updatedByRemote(call: Call) {
        NLog.e("updatedByRemote")
        answerCallVideoUpdateRequest(call, true)
        for (callBack in callStateCallBacks) {
            callBack.updatedByRemote(call)
        }
    }

    /**
     * 远端更新状态自动确定
     */
    fun answerCallVideoUpdateRequest(call: Call, accept: Boolean) {
        val params = coreContext.core.createCallParams(call)
        NLog.e("answerCallVideoUpdateRequest videoEnabled ${params?.isVideoEnabled}")

        if (accept) {
            if (params?.isVideoEnabled == true) {
                params?.isVideoEnabled = true
                coreContext.core.isVideoCaptureEnabled = true
                coreContext.core.isVideoDisplayEnabled = true
            }

        } else {
            params?.isVideoEnabled = false
        }

        call.acceptUpdate(params)
    }

    /**
     * 设置要显示视频的本地TextureView
     */
    fun setVideoWindowId(videoRendering: TextureView, videoPreview: TextureView) {
        coreContext.core.nativeVideoWindowId = videoRendering
        coreContext.core.nativePreviewWindowId = videoPreview
    }

    init {
//        coreContext.core.addListener(coreListener)
        callTimeoutHandler = Handler(Looper.getMainLooper())
    }

    /**
     * 是否开启麦克风
     */
    fun isMicEnabled(): Boolean = coreContext.core.isMicEnabled

    /**
     * 打开/关闭
     * 麦克风
     */
    fun setMicEnabled(enable: Boolean) {
        coreContext.core.isMicEnabled = enable
    }

    /**
     * 打开/关闭语音流
     */
    fun setAudioStreamMute(isMute: Boolean) {
        coreContext.core.setAudioStreamMuteRecvRtp(isMute)
    }

    fun setSpeakerVolume(call: Call?, volume: Float) {
        call?.speakerVolumeGain = volume
    }

    /**
     * 获取远端sip账号
     */
    fun getRemoteSipAccount(): String? {
        return coreContext.core.currentCallRemoteAddress?.username ?: null
    }

    /**
     * 获取远端来电的sip用户名
     */
    fun getRemoteSipAccount(currentCall: Call?): String? {
        return currentCall?.remoteAddress?.username ?: null
    }

    /**
     * 获取对端显示名
     */
    fun getRemoteUsername(): String {
        var displayName = ""
        //coreContext.core.currentCall获取的当前call不准确,需要根据call的状态区分
        var currentCall = findActiveCall()

        val sessionName = currentCall?.params?.sessionName

        if (!sessionName.isNullOrEmpty()) {
            displayName = sessionName
        } else {
            if (displayName.isNullOrEmpty()) {
                displayName =
                    currentCall?.remoteAddress?.displayName ?: currentCall?.remoteAddress?.username
                            ?: ""
            }
        }
        displayName = recoverSpecialSymbol(displayName)
        NLog.e(" getRemoteUsername  sessionName:$sessionName  displayName:$displayName")
        return displayName
    }

    /**
     * 获取当前的call,可能会存在多路来电的情况
     */
    fun findActiveCall(): Call? {
        for (call in NL_App.coreContext.core.calls) {
            Log.e("[Call Activity]  state:${call.state}")

            //优先获取已接听的通话
            if (call.state == Call.State.Connected || call.state == Call.State.StreamsRunning) {
                return call
            }
            if (call.state == Call.State.IncomingReceived ||
                call.state == Call.State.IncomingEarlyMedia
            ) {
                return call
            }
        }
        return coreContext.core.currentCall
    }

    /**
     * 截图
     */
//    fun takeScreenshot() {
//        val currentCall = coreContext.core.currentCall
//        if (currentCall != null) {
//            if (currentCall.currentParams.isVideoEnabled) {
//                val fileName = System.currentTimeMillis().toString() + ".jpeg"
//                val filePath = FileUtils.getFileStoragePath(fileName).absolutePath
//                NLog.e(" takeScreenshot  $filePath")
//                currentCall.takeVideoSnapshot(filePath)
//                if (File(filePath).exists()) {
//                    showToast("截图成功! 图片路径:\n\r$filePath")
//                } else {
//                    showToast("截图失败! 图片未能保存")
//                }
//            } else {
//                NLog.e("video is not enable")
//            }
//        }
//    }

//    fun takeScreenshot(activity: Activity, deviceName: String?) {
//        val currentCall = coreContext.core.currentCall
//        if (currentCall != null) {
//            if (currentCall.currentParams.isVideoEnabled) {
//                val fileName = deviceName + "@@@" + System.currentTimeMillis().toString() + ".jpeg"
////                val fullPath = "Hello"+File.separator+ fileName
//                val filePath = FileUtils.getFileStoragePath(fileName).absolutePath
//
//                NLog.e(" takeScreenshot :: $filePath")
//                thread {
//                    val result = currentCall.takeVideoSnapshot(filePath)
//                    NLog.e("<jake> ..screenshot result = $result")
//                    val resultStr = if (result == 0) {
//                        NLog.e("screenshot success!!!!!")
//                        getString(R.string.result_success)
//                    } else {
//                        NLog.e("screenshot failed!!!!!")
//                        getString(R.string.result_failure)
//                    }
//                    printAllFiles()
//
//                    activity.runOnUiThread {
//                        showToast(getString(R.string.function_shortcut)+"$resultStr")
//                    }
//                }
//                NLog.e(" ---click screenshot---")
//            } else {
//                NLog.e("video is not enable")
//            }
//        }
//    }
    /**
     * 截图
     */
//    fun takeScreenshot(deviceName: String?) {
//        val currentCall = coreContext.core.currentCall
//        if (currentCall != null) {
//            if (currentCall.currentParams.isVideoEnabled) {
//                val fileName = deviceName + "_" + System.currentTimeMillis().toString() + ".jpeg"
//                val filePath = FileUtils.getFileStoragePath(fileName).absolutePath
//
//                NLog.e(" takeScreenshot :: $filePath")
//                thread {
//                    val result = currentCall.takeVideoSnapshot(filePath)
//                    NLog.e("screenshot result = $result")
//                    if (result == 0) {
////                        showToast("截图成功! 图片路径:\n\r$filePath")
//                        NLog.e("screenshot success!!!!!")
//                    } else {
////                        showToast("截图失败! 图片未能保存")
//                        NLog.e("screenshot failed!!!!!")
//                    }
//                    printAllFiles()
//                    NLog.e(" ---截图完毕---")
//                }
//                NLog.e(" ---执行结束---")
//            } else {
//                NLog.e("video is not enable")
//            }
//        }
//    }
//
//    fun printAllFiles() {
//        val file = FileUtils.getFileStorageDir(true)
//        val tempList: Array<File> = file.listFiles()
//        for (i in tempList.indices) {
//            if (tempList[i].isFile) {
//                val fileName  = "${file.path}/${tempList[i].name}"
//                NLog.e("<jake>..file is $fileName")
//            }
//        }
//    }
//
//    fun clearUnuseImage() {
//
//        val file = FileUtils.getFileStorageDir(true)
//        val tempList: Array<File> = file.listFiles()
//        for (i in tempList.indices) {
//            if (tempList[i].isFile) {
//                val fileName  = "${file.path}/${tempList[i].name}"
//                NLog.e(" getAllScreenshot  ---->  $fileName")
//                if (fileName.endsWith(".part")) {    //  根据自己的需要进行类型筛选
//                    File(fileName).delete()
//                }
//            }
//        }
//         val fs = file.listFiles()
//        NLog.e(" getAllScreenshot  ${fs.size}")
//    }
//
//    /**
//     * 获取所有的截图
//     */
//    fun getAllScreenshot(): ArrayList<String>? {
//        val fileList: ArrayList<String> = ArrayList()
//        val file = FileUtils.getFileStorageDir(true)
//        val tempList: Array<File> = file.listFiles()
//        for (i in tempList.indices) {
//            if (tempList[i].isFile) {
//                val fileName  = "${file.path}/${tempList[i].name}"
//                NLog.e("<jake> getAllScreenshot  ---->  $fileName")
//                if (fileName.endsWith(".jpeg")) {    //  根据自己的需要进行类型筛选
//                    fileList.add(fileName)
//                }
//            }
//        }
//        Collections.sort(fileList , Comparator { o1, o2 ->
//            try {
//                val time1 = o1.substringAfter("@@@").substringBefore(".jpeg").toLong()
//                val time2 = o2.substringAfter("@@@").substringBefore(".jpeg").toLong()
//                time1.compareTo(time2)
//            } catch (e: Exception) {
//                e.printStackTrace()
//                o1.compareTo(o2)
//            }
//        } )
//        NLog.e("<jake> getAllScreenshot  ${fileList.size}")
//        return fileList
//    }
//
//    fun removeAllScreenshot() {
//        val file = FileUtils.getFileStorageDir(true)
//        val tempList: Array<File> = file.listFiles()
//        for (i in tempList) {
//            removeScreenshot(i.absolutePath)
//        }
////        for (i in tempList.indices) {
////            if (tempList[i].isFile) {
////                removeScreenshot(i)
////            }
////        }
//    }
//
//
    fun removeScreenshot(path: String): Boolean {
        try {
            val fileLocal = File(path)
            if (fileLocal.exists()) {
                fileLocal.delete()
            }
            return true
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return false
    }


    /**
     * 录屏开关
     */
    fun toggleRecording(status: Boolean) {
        val currentCall = coreContext.core.currentCall
        if (currentCall != null) {
            var filePath = currentCall.params.recordFile
            NLog.e(" toggleRecording  $filePath")
            when (status) {
                true -> {
                    if (!currentCall.isRecording) {
                        currentCall.startRecording()
                        showToast("开始录屏!")
                    } else {
                        showToast("视频正在录制!")
                    }
                }

                false -> {
                    if (currentCall.isRecording) {
                        currentCall.stopRecording()
                        showToast("结束录屏! 视频路径:\n\r$filePath")
                    } else {
                        showToast("视频未在录制!")
                    }
                }
            }
        }
    }

    /**
     * 判断当前call是否在呼出状态
     */
    fun findOutgoingCall(): Boolean {
        for (call in coreContext.core.calls) {
            if (call.state == Call.State.OutgoingInit ||
                call.state == Call.State.OutgoingProgress ||
                call.state == Call.State.OutgoingRinging ||
                call.state == Call.State.OutgoingEarlyMedia
            ) {
                return true
            }
        }
        return false
    }

    /**
     * 是否自动接听视频电话
     */
    private fun autoAcceptVideo(auto: Boolean) {
        val policy = coreContext.core.videoActivationPolicy
        policy.automaticallyAccept = auto
        policy.automaticallyInitiate = true
        coreContext.core.videoActivationPolicy = policy
    }

    /**
     * 获取正在通话个数
     */
    fun getCallsNumbers(): Int {
        val core = coreContext.core
        return core.callsNb
    }


    /**
     * 扬声器是否打开
     */
    fun isSpeakerOpen(): Boolean {
        val currentAudioDevice = coreContext.core.currentCall?.outputAudioDevice
        return currentAudioDevice?.type == AudioDevice.Type.Speaker
    }

    /**
     * 扬声器和听筒切换
     */
    fun routeAudioToSpeaker(enable: Boolean) {
        NLog.d("routeAudioToSpeaker enable:$enable")
        for (audioDevice in coreContext.core.audioDevices) {
            if (!enable && audioDevice.type == AudioDevice.Type.Earpiece) {
                // 听筒
                coreContext.core.currentCall?.outputAudioDevice = audioDevice
                NLog.d("setOutputAudioDevice to Earpiece")
                break
            } else if (enable && audioDevice.type == AudioDevice.Type.Speaker) {
                // 扬声器
                coreContext.core.currentCall?.outputAudioDevice = audioDevice
                NLog.d("setOutputAudioDevice to Speaker")
                break
            } else {
                NLog.d("routeAudioToSpeaker other ${audioDevice.type}")
            }
        }
    }

    /**
     * 发送Dtmf码
     */
    fun sendDtmfCode(dtmf: String) {
        val currentCall: Call? = coreContext.core.currentCall
        if (currentCall !== null) {
            currentCall.sendDtmfs(dtmf)
        }
    }

    /**
     * 更新SIP账号的DisplayName
     */
    fun updateDisplayName(displayName: String?) {
        val defaultAccount = coreContext.core.defaultAccount ?: return
        val params = defaultAccount?.params?.clone()
        val identity = params?.identityAddress?.clone()
        if (identity != null) {
            identity.displayName = displayName
            params?.identityAddress = identity
            defaultAccount?.params = params
        } else {
            NLog.e("[Account Settings] Account doesn't have an identity yet")
        }
    }

    fun destroy() {
        NL_App.exitCoreService()
    }

    fun ensureIpv6Disabled() {
        if (coreContext.core.isIpv6Enabled) {
            coreContext.core.isIpv6Enabled = false
        }
    }

    fun isAccountExis() = coreContext.core.defaultAccount != null

    //获取当前注册的状态
    fun getCurrentRegistrationState(): Int {
        return coreContext.core.defaultAccount?.state?.toInt() ?: 0
    }

    //开启和禁用sip账号
    fun activeSipAccount(active: Boolean) {
        NLog.d("activeSipAccount() active:$active")
        for (account in coreContext.core.accountList) {
            val params = account.params.clone()
            params.isRegisterEnabled = active
            account.params = params
        }
    }

    fun refreshRegisterIfNeeded() {
        for (account in coreContext.core.accountList) {
            NLog.d("refreshAllRegister() preState:${account.state}  identityAddress:${account.params.identityAddress?.asStringUriOnly()}")
            //如果当前注册状态是Failed,手动刷新下注册状态,防止kcp连接后没有主动发起注册
            if (account.state == RegistrationState.Failed) {
                account.refreshRegister()
            }
            if (account.state == RegistrationState.Progress) {
                //TODO 当处于Progress状态时,有时候kcp是已连接状态仍然会注册失败,临时优化在coreContext中监听Failed状态重新发起一次注册
//                account.refreshRegister()
            }
        }
    }

    fun ifNeedForbiddenCall() {
        val currentCall = coreContext.core.currentCall
        NLog.e("forbiddenCall currentCall ... ${currentCall?.dir} ${currentCall?.state}")
        currentCall?.let {
            GlobalScope.launch(Dispatchers.Main) {
                if (it.state == Call.State.IncomingReceived || it.state == Call.State.IncomingEarlyMedia) {
                    showToast(getString(R.string.rntc_error_code_server_reject))
                    currentCall?.decline(Reason.Forbidden)
                }
                if (it.dir == Call.Dir.Outgoing && (it.state == Call.State.StreamsRunning || it.state == Call.State.OutgoingRinging)) {
                    showToast(getString(R.string.rntc_error_code_server_reject))
                    hangUp()
                }
            }
        }
    }

    fun terminateCall() {
        coreContext.core.currentCall?.terminate()
        callTimeoutRunnable?.let {
            callTimeoutHandler?.removeCallbacks(it)
        }
    }

    //更新sip注册的代理地址和端口号&&strict proxy配置
    fun updateRegisteredProxyAddress() {
        //TODO 后续kcp端口号会做成动态的,需要在每次kcp连接成功后更新SIP注册的代理地址、端口和相关配置
        NLog.d("updateRegisteredProxyAddress...")

//        val sipServer = KcpManager.instance.nativeGetRntcSipServer()
//        val sipPort = KcpManager.instance.nativeGetRntcSipPort()
//
//        val core = coreContext.core
//
//        core.setStrictProxyAddress(sipServer)
//        core.setStrictProxyPort(sipPort)
//
//        val account = core.defaultAccount ?: return
//        val params = account?.params?.clone()
//        val newServerAddress = params?.serverAddress?.clone()
//
//        //端口号发生变化再去更新代理地址
//        if(sipPort != newServerAddress?.port) {
//            newServerAddress?.domain = sipServer
//            newServerAddress?.port = sipPort
//            params?.serverAddress = newServerAddress
//
//            if (params != null) {
//                account?.params = params
//            }
//        }
    }

    fun resumeCall(call: Call?) {
        call?.resume()
    }

    fun isFirstCallInMonitor(): Boolean {
        val firstCall = coreContext.core.calls.firstOrNull()
        return firstCall?.params?.getCustomHeader(NL_Key.CALL_INFO) == NL_Key.EXTRA_MONITOR
    }

    //根据来电的Aid动态开启acceptEarlyMedia
    fun acceptEarlyMediaBaseOnRemoteAid(aid: String, enableEarlyMedia: Boolean? = false) {
        //先根据设备类型判断再根据sipMessage解析的属性判断
        val remoteDeviceData =
            BaseApplication.getDeviceDataByUsername(aid)
        if (remoteDeviceData != null) {
            corePreferences.acceptEarlyMedia =
                corePreferences.globalSupportEarlyMedia && (remoteDeviceData?.devType == Base_DeviceType.DOORPHONE.code)
        } else {
            corePreferences.acceptEarlyMedia =
                corePreferences.globalSupportEarlyMedia && enableEarlyMedia == true
        }

        NLog.d("acceptEarlyMediaBaseOnRemoteAid aid:$aid devType:${remoteDeviceData?.devType} enableEarlyMedia:$enableEarlyMedia acceptEarlyMedia:${corePreferences.acceptEarlyMedia}")
    }
}